<?php 
// +---------------------------------------------------------------
// | Package: Tommy Framework
// +---------------------------------------------------------------
// | Version $Id: View.class.php 2010-3-30 12:30:30 $
// +---------------------------------------------------------------
// | Copyright (c) 2009 http://www.tommyframework.com All rights reserved.
// +---------------------------------------------------------------
// | Author: tommy <service@tommyframework.com>
// +---------------------------------------------------------------

if(!defined('IN_TOMMY')){
	exit;
}
class View extends Base{

	//定义变量
	private static $instance; //用于构建类的singleton模式参数
	
	public $template_dir; //模板文件文件夹路径
	public $compile_dir; //编译文件文件夹路径
	public $left_delimiter; //模板标签左侧边限字符.
	public $right_delimiter; //模板标签右侧边限字符.
	protected $tpl_vars; //用于assign的赋值，临时数组
	
	/**
     +----------------------------------------------------------
     * 构造函数,用于初始化运行环境.
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @return mixed
     +----------------------------------------------------------
     */
	public function __construct(){
		$this->tpl_vars = array();		
		//设置默认模板文件，编译文件目录
		$this->template_dir = APP_ROOT.'/views/';
		$this->compile_dir = APP_ROOT.'/cache/template_c/';
		//定义模板标签的边限字符.
		$this->left_delimiter = '<!--\s?{';
		$this->right_delimiter = '}\s?-->';
		return true;
	}
	
	//分析文件名,用于处理模板文件及编译文件的文件名.
	protected function parse_file_name($filename=false){
		$controller_name = strtolower(substr(Tommy::$controller, 0, -10));
		//当参数为空时.
		if(empty($filename)){
			$file_name = $controller_name.'/'.substr(Tommy::$action, 0, -6);
		}
		else {
			if(strpos($filename,'/')){
				$filename_array = explode('/',$filename);
				$file_name = $filename_array[0].'/'.$filename_array[1];
			}
			else {
				$file_name = $controller_name.'/'.$filename;
			}
		}
		return $file_name;
	}
	
	//获取模板文件.
	protected function parse_template_file($filename=false){
		//分析参数,获取文件名.
		$file_name = $this->parse_file_name($filename);
		return $this->template_dir.$file_name.'.html';
	}
	
	//获取编译文件.
	protected function parse_compile_file($filename=false){
		//分析参数,获取文件名.
		$file_name = $this->parse_file_name($filename);
		return $this->compile_dir.$file_name.'.php';
	}
	
	//分析编译文件,是否需要重新创建编译文件.
	public function check_compile_file($template_file,$compile_file){
		return (file_exists($compile_file)&&filemtime($compile_file)>=filemtime($template_file)) ? false : true;
	}
	
	//创建编译文件.
	public function create_compile_file($compile_file,$content){
		//判断编译目录是否存在，如不存在则自动创建.
		$compile_dir = dirname($compile_file);
		if(!is_dir($compile_dir)){	
			mkdir($compile_dir, 0777);
		}
		else {
			//如果编译目录不可写入,则改变文件模式.
			if(!is_writable($compile_dir))
				chmod($compile_dir,0777);
		}
		//将编译文件内容写入编译文件.
		file_put_contents($compile_file,$content,LOCK_EX);
		return true;
	}
	
	//加载模板文件,即获取模板文件内容.
	public function load_template_file($template_file){
		//查看模板文件是否存在.
		if(!file_exists($template_file)){
			trigger_error('The template file:'.$template_file.' is not exists!',E_USER_ERROR);
		}
		$content = file_get_contents($template_file);
		return $this->handle_template_file($content);
	}
	
	//加载编译文件,即获取编译文件内容.
	public function load_compile_file($compile_file){
		if(file_exists($compile_file)){
			include($compile_file);
			return true;
		}
		else {
			return false;
		}
	}
	
	//输出模板内容.
	public function display($filename=false){
		//获取模板文件及编译文件.
		$template_file = $this->parse_template_file($filename);
		$compile_file = $this->parse_compile_file($filename);
		//判断编译文件是否需要重新写入.
		$this->handle_load_compile($template_file, $compile_file);
		return true;
	}
	
	//处理布局,模板标签include的部分.
	protected function layout($filename){
		if(empty($filename))
			return false;
		//获取文件名.
		if(strpos($filename,'/')){
			$filename_array = explode('/',$filename);
			$file_name = $filename_array[0].'/'.$filename_array[1];
		}
		else {
			$file_name = strtolower(substr(Tommy::$controller, 0, -10)).'/'.$filename;
		}
		$template_file = $this->template_dir.$file_name.'.html';
		$compile_file = $this->compile_dir.$file_name.'.inc.php';
		//判断编译文件是否需要重新写入.
		$this->handle_load_compile($template_file, $compile_file);
		return true;
	}
	
	//处理widget,模板标签widget的部分.
	public function widget($file_name){
		if(empty($file_name))
			return false;
		//获取文件名.
		$template_file = APP_ROOT.'/widgets/views/'.$file_name.'.html';
		$compile_file = APP_ROOT.'/cache/widget/'.$file_name.'.php';
		//判断编译文件是否需要重新写入.
		$this->handle_load_compile($template_file, $compile_file);
		return true;
	}
	
	//处理加载编译文件.
	protected function handle_load_compile($template_file,$compile_file){
		//判断编译文件是否需要重新写入.
		if($this->check_compile_file($template_file, $compile_file)){
			$template_content = $this->load_template_file($template_file);
			$this->create_compile_file($compile_file,$template_content);
		}
		//加载编译文件
		$this->load_compile_file($compile_file);
	}
	//处理模板文件的模板标签,即过滤 <!--{}-->
	protected function handle_template_file($content){
		//待处理的模板标签
		$Regexp_array = array(
		'#'.$this->left_delimiter.'\s*\$(\w+?)\s*'.$this->right_delimiter.'#i',
		'#'.$this->left_delimiter.'\s*\$(\w+?)\[\'(\w+?)\'\]\s*'.$this->right_delimiter.'#i',
		'#'.$this->left_delimiter.'\s*include\s+(.*?)\s*'.$this->right_delimiter.'#is',
		'#'.$this->left_delimiter.'\s*widget\s+(.*?)\s*'.$this->right_delimiter.'#is',
		'#'.$this->left_delimiter.'eval\s+(.+?)'.$this->right_delimiter.'#is',

		'#'.$this->left_delimiter.'echo\s+(.+?)\s\$(\w+?)\s(.+?)'.$this->right_delimiter.'#is',
		'#'.$this->left_delimiter.'echo\s+\$(\w+?)\[\'(\w+?)\'\]\s*'.$this->right_delimiter.'#is',
		'#'.$this->left_delimiter.'echo\s+\$(\w+?)\[\'(\w+?)\'\](.+?)'.$this->right_delimiter.'#is',
		'#'.$this->left_delimiter.'echo\s+\$(\w+?)\s(.+?)'.$this->right_delimiter.'#is',
		'#'.$this->left_delimiter.'echo\s+\$(\w+?)\s*'.$this->right_delimiter.'#is',
		'#'.$this->left_delimiter.'echo\s+(.+?)\$(\w+?)\[\'(\w+?)\'\](.+?)'.$this->right_delimiter.'#is',
		'#'.$this->left_delimiter.'echo\s+(.+?)'.$this->right_delimiter.'#is',

		'#'.$this->left_delimiter.'\s*if\s+\$(\w+?)\s*([>|<])\s*\$(\w+?)\s*'.$this->right_delimiter.'#i',
		'#'.$this->left_delimiter.'\s*if\s+\$(\w+?)\s*([>|<|!|=]=)\s*\$(\w+?)\s*'.$this->right_delimiter.'#i',
		'#'.$this->left_delimiter.'\s*if\s+\$(\w+?)\s*([>|<])\s*(\w+?)\s*'.$this->right_delimiter.'#i',
		'#'.$this->left_delimiter.'\s*if\s+\$(\w+?)\s*([>|<|!|=]=)\s*(\w+?)\s*'.$this->right_delimiter.'#i',

		'#'.$this->left_delimiter.'\s*else\s*if\s+\$(\w+?)\s*([>|<])\s*\$(\w+?)\s*'.$this->right_delimiter.'#i',
		'#'.$this->left_delimiter.'\s*else\s*if\s+\$(\w+?)\s*([>|<|!|=]=)\s*\$(\w+?)\s*'.$this->right_delimiter.'#i',
		'#'.$this->left_delimiter.'\s*else\s*if\s+\$(\w+?)\s*([>|<])\s*(\w+?)\s*'.$this->right_delimiter.'#i',
		'#'.$this->left_delimiter.'\s*else\s*if\s+\$(\w+?)\s*([>|<|!|=]=)\s*(\w+?)\s*'.$this->right_delimiter.'#i',

		'#'.$this->left_delimiter.'\s*if\s+\$(\w+?)\[\'(\w+?)\'\]\s*([>|<])\s*\$(\w+?)\s*'.$this->right_delimiter.'#i',
		'#'.$this->left_delimiter.'\s*if\s+\$(\w+?)\[\'(\w+?)\'\]\s*([>|<|!|=]=)\s*\$(\w+?)\s*'.$this->right_delimiter.'#i',
		'#'.$this->left_delimiter.'\s*if\s+\$(\w+?)\[\'(\w+?)\'\]\s*([>|<])\s*(\w+?)\s*'.$this->right_delimiter.'#i',
		'#'.$this->left_delimiter.'\s*if\s+\$(\w+?)\[\'(\w+?)\'\]\s*([>|<|!|=]=)\s*(\w+?)\s*'.$this->right_delimiter.'#i',

		'#'.$this->left_delimiter.'\s*else\s*if\s+\$(\w+?)\[\'(\w+?)\'\]\s*([>|<])\s*\$(\w+?)\s*'.$this->right_delimiter.'#i',
		'#'.$this->left_delimiter.'\s*else\s*if\s+\$(\w+?)\[\'(\w+?)\'\]\s*([>|<|!|=]=)\s*\$(\w+?)\s*'.$this->right_delimiter.'#i',
		'#'.$this->left_delimiter.'\s*else\s*if\s+\$(\w+?)\[\'(\w+?)\'\]\s*([>|<])\s*(\w+?)\s*'.$this->right_delimiter.'#i',
		'#'.$this->left_delimiter.'\s*else\s*if\s+\$(\w+?)\[\'(\w+?)\'\]\s*([>|<|!|=]=)\s*(\w+?)\s*'.$this->right_delimiter.'#i',

		'#'.$this->left_delimiter.'\s*else\s*'.$this->right_delimiter.'#i',
		'#'.$this->left_delimiter.'\s*\/if\s*'.$this->right_delimiter.'#i',
		'#'.$this->left_delimiter.'\s*loop\s+\$(\w+?)\s+\$(\w+?)\s*'.$this->right_delimiter.'#i',
		'#'.$this->left_delimiter.'\s*loop\s+\$(\w+?)\s+\$(\w+?)\s?=>\s?\$(\w+?)\s*'.$this->right_delimiter.'#i',
		'#'.$this->left_delimiter.'\s*\/loop\s*'.$this->right_delimiter.'#i',
		);
		//被替换的编译语句.
		$Replace_array = array(
		"<?php echo \$this->tpl_vars['\\1']; ?>",
		"<?php echo \$this->tpl_vars['\\1']['\\2']; ?>",
		"<?php \$this->layout('\\1'); ?>",
		"<?php Widget::render('\\1'); ?>",
		"<?php \\1 ?>",
		
		"<?php echo \\1\$this->tpl_vars['\\2']\\3; ?>",
		"<?php echo \$this->tpl_vars['\\1']['\\2']; ?>",
		"<?php echo \$this->tpl_vars['\\1']['\\2']\\3; ?>",	
		"<?php echo \$this->tpl_vars['\\1']\\2; ?>",
		"<?php echo \$this->tpl_vars['\\1']; ?>",
		"<?php echo \\1\$this->tpl_vars['\\2']['\\3']\\4; ?>",
		"<?php echo \\1; ?>",
			
		"<?php\r\nif(\$this->tpl_vars['\\1']\\2\$this->tpl_vars['\\3']){\r\n?>",
		"<?php\r\nif(\$this->tpl_vars['\\1']\\2\$this->tpl_vars['\\3']){\r\n?>",
		"<?php\r\nif(\$this->tpl_vars['\\1']\\2\\3){\r\n?>",
		"<?php\r\nif(\$this->tpl_vars['\\1']\\2\\3){\r\n?>",

		"<?php\r\n}\r\nelse if(\$this->tpl_vars['\\1']\\2\$this->tpl_vars['\\3']){\r\n?>",
		"<?php\r\n}\r\nelse if(\$this->tpl_vars['\\1']\\2\$this->tpl_vars['\\3']){\r\n?>",
		"<?php\r\n}\r\nelse if(\$this->tpl_vars['\\1']\\2\\3){\r\n?>",
		"<?php\r\n}\r\nelse if(\$this->tpl_vars['\\1']\\2\\3){\r\n?>",

		"<?php\r\nif(\$this->tpl_vars['\\1']['\\2']\\3\$this->tpl_vars['\\4']){\r\n?>",
		"<?php\r\nif(\$this->tpl_vars['\\1']['\\2']\\3\$this->tpl_vars['\\4']){\r\n?>",
		"<?php\r\nif(\$this->tpl_vars['\\1']['\\2']\\3\\4){\r\n?>",
		"<?php\r\nif(\$this->tpl_vars['\\1']['\\2']\\3\\4){\r\n?>",

		"<?php\r\n}\r\nelse if(\$this->tpl_vars['\\1']['\\2']\\3\$this->tpl_vars['\\4']){\r\n?>",
		"<?php\r\n}\r\nelse if(\$this->tpl_vars['\\1']['\\2']\\3\$this->tpl_vars['\\4']){\r\n?>",
		"<?php\r\n}\r\nelse if(\$this->tpl_vars['\\1']['\\2']\\3\\4){\r\n?>",
		"<?php\r\n}\r\nelse if(\$this->tpl_vars['\\1']['\\2']\\3\\4){\r\n?>",

		"<?php\r\n}\r\nelse{\r\n?>",
		"<?php\r\n}\r\n?>",
		"<?php\r\nif(is_array(\$this->tpl_vars['\\1'])){\r\n\tforeach(\$this->tpl_vars['\\1'] as \$this->tpl_vars['\\2']){\r\n?>",
		"<?php\r\nif(is_array(\$this->tpl_vars['\\1'])){\r\n\tforeach(\$this->tpl_vars['\\1'] as \$this->tpl_vars['\\2']=>\$this->tpl_vars['\\3']){\r\n?>",
		"<?php\r\n\t}\r\n}\r\n?>",
		);
		//将模板内容进行匹配处理.
		return preg_replace($Regexp_array,$Replace_array,$content);
	}
	
	//对模板变量进行赋值
	public function assign($handle,$value=false){
		//当$handle为组时
		if(is_array($handle)){	
			foreach ($handle as $key=>$val){	
				$this->tpl_vars[$key] = $val;
			}
		}
		else{
			$this->tpl_vars[$handle] = $value;
		}
		return true;
	}
	
	//析构函数，清空所有的临时变量
	public function __destruct(){
		//清空不必要的内存占用.
		$this->tpl_vars = array();
	}
	
	/**
     +----------------------------------------------------------
     * 用于本类的静态调用,子类需要重载才能正常使用.
     +----------------------------------------------------------
     * @access public
     +----------------------------------------------------------
     * @param string $params 类的名称
     +----------------------------------------------------------
     * @return void
     +----------------------------------------------------------
     */
    public static function getInstance(){		
		if(self::$instance == null){		
			self::$instance = new self;
		}		
		return self::$instance;
	}
}
?>